<template>
  <div>
    <ul>
      <li :draggable="isDraggable"
          @dragstart.stop="handleDragStart($event)"
          @dragenter="handleDragEnter"
          @dragleave="handleDragLeave"
          @dragover.prevent="handleDragOver"
          @drop.stop="handleDrop($event)"
          @dragend.prevent="handleDragEnd"
          :class="isRoot?'rootLi':'nodeLi'">
        <div class="divNode">
          <oolongIcon @click="toggle" type="android-arrow-dropright-circle" v-if="!node.open&&isFolder"
                      size="32" color="grey"></oolongIcon>
          <oolongIcon @click="toggle" type="android-arrow-dropdown-circle" v-if="node.open&&isFolder"
                      size="32" color="#FF9900"></oolongIcon>
          <oolongIcon @click="toggle" type="android-arrow-dropright-circle" v-show="!isFolder"
                      size="32" color="#ffffff"></oolongIcon>
          <div v-show="node.showCheckBox" v-if="useCheckBox">
            <oolongIcon @click="selectCheck" type="ios-checkmark-outline" size="32" :color="CheckBox"
                        v-show="Check"></oolongIcon>
            <oolongIcon @click="selectCheck" type="ios-circle-filled" size="32" :color="CheckBox"
                        v-show="isIndeterminate"></oolongIcon>
            <oolongIcon @click="selectCheck" type="ios-circle-outline" size="32" :color="CheckBox"
                        v-show="unCheck"></oolongIcon>
          </div>
          <div>
            <a @click="selectCheck" @dblclick="showNodeDetail()" v-if="nodeDoubleClick">{{ node.name }}</a>
            <oolongInput v-model="node.name" @keyup.enter="editorNode" size="large" style="margin-bottom: 12px;"
                         readonly
                         v-else/>
          </div>
          <div v-if="showOperators">
            <div v-if="showEditorOperator">
              <div v-show="node.addNodeBtn">
                <oolongIcon @click="editorNode" type="compose" size="32" color="#B377A5"></oolongIcon>
              </div>
            </div>
            <div v-if="showRemoveOperator">
              <div v-show="node.addNodeBtn">
                <oolongIcon @click="removeNode" type="android-cancel" size="32" color="#FF5151"></oolongIcon>
              </div>
            </div>
            <div v-if="showAddBrotherOperator">
              <div v-show="node.addNodeBtn">
                <oolongIcon @click="addBrotherNode" type="fork-repo" size="32" color="#48b1bb"></oolongIcon>
              </div>
            </div>
            <div v-if="showAddChildOperator">
              <div v-show="node.addNodeBtn">
                <oolongIcon @click="addChildNode" type="merge" size="32" color="#48b1bb"></oolongIcon>
              </div>
            </div>
          </div>
        </div>
        <!--子节点的内容-->
        <div v-show="node.open" v-if="isFolder">
          <menu-tree v-for="(nodeNode,index) in node.menuChild" :key="index"
                     :tree-node="nodeNode"
                     :useCheckBox="useCheckBox"
                     :checkBoxDisabled="checkBoxDisabled"
                     :showOperators="showOperators"
                     :showEditorOperator="showEditorOperator"
                     :showRemoveOperator="showRemoveOperator"
                     :showAddBrotherOperator="showAddBrotherOperator"
                     :showAddChildOperator="showAddChildOperator"
                     :isDraggable="isDraggable"
                     :draggableMode="draggableMode"
                     :nodeDoubleClick="nodeDoubleClick"
                     :isRoot="false"
                     @updateCheckBox="childUpdateCheckBox"
                     @showNodeDetail="childShowNodeDetail"
                     @addChildNode="childAddChildNode"
                     @editorNode="childEditorNode"
                     @addBrotherNode="childAddBrotherNode"
                     @removeNode="childRemoveTreeNode"
                     @handleDrop="childHandleDrop"
          ></menu-tree>
        </div>
      </li>
    </ul>
  </div>
</template>
<script>
import {oneOf} from '../../utils/assist';

export default {
  data: function () {
    return {
      node: this.treeNode
    };
  },
  name: 'menu-tree',
  props: {
    // 根节点不偏移
    isRoot: {
      type: Boolean,
      default: function () {
        return true;
      }
    },
    nodeDoubleClick: {
      type: Boolean,
      default: function () {
        return true;
      }
    },
    isDraggable: {
      type: Boolean,
      default: function () {
        return true;
      }
    },
    draggableMode: {
      validator(value) {
        return oneOf(value, ['ALL', 'FROM', 'TO']);// From To 用于A树向B树拖拽
      },
      default: 'ALL'
    },
    showEditorOperator: {
      type: Boolean,
      default: function () {
        return true;
      }
    },
    showRemoveOperator: {
      type: Boolean,
      default: function () {
        return true;
      }
    },
    showAddBrotherOperator: {
      type: Boolean,
      default: function () {
        return true;
      }
    },
    showAddChildOperator: {
      type: Boolean,
      default: function () {
        return true;
      }
    },
    showOperators: {
      type: Boolean,
      default: function () {
        return true;
      }
    },
    treeNode: {
      type: Object,
      default: function () {
        return {};
      }
    },
    useCheckBox: {
      type: Boolean,
      default: function () {
        return true;
      }
    },
    checkBoxDisabled: {
      type: Boolean,
      default: function () {
        return true;
      }
    }
  },
  // 计算属性 判断节点是否展开
  computed: {
    isFolder: function () {
      return this.node.menuChild && this.node.menuChild.length;
    },
    Check: function () {
      return this.node.isCheck && !this.node.indeterminate;
    },
    unCheck: function () {
      return !this.node.isCheck && !this.node.indeterminate
    },
    isIndeterminate: function () {
      return this.node.indeterminate;
    },
    CheckBox: function () {
      return this.checkBoxDisabled ? 'grey' : '';
    }
  },
  methods: {
    // 当前组件的按钮事件绑定处理
    // 双击事件点击传输节点数据
    showNodeDetail() {
      let jsonNode = this.node;
      this.$emit('showNodeDetail', jsonNode);
    },
    // 编辑当前节点
    editorNode() {
      let jsonNode = this.node;
      this.$emit('editorNode', jsonNode);
    },
    // 添加当前节点的子节点
    addChildNode: function () {
      let jsonNode = this.node;
      this.$emit('addChildNode', jsonNode);
    },
    // 添加当前节点的兄弟节点
    addBrotherNode() {
      let jsonNode = this.node;
      this.$emit('addBrotherNode', jsonNode);
    },
    // 删除当前节点
    removeNode() {
      let jsonNode = this.node;
      this.$emit('removeNode', jsonNode);
    },
    // 拖动 元素被放到了放置目标中触发
    handleDrop: function (e) {
      // 拖拽的虚拟节点
      let vm = window.__drop_node__;
      vm.$el.style.backgroundColor = '';
      this.$el.style.backgroundColor = '';
      // 目标节点
      let __parent__ = this;
      // 目标节点向上递归查看父节点 如果父节点中有拖拽的节点 中断函数返回
      while (__parent__ !== undefined) {
        // 拖拽的节点和目标节点是同一个节点 中断
        if (__parent__ === vm) {
          return;
        }
        // 获取目标节点的父节点
        __parent__ = __parent__.$parent;
        // 父节点区域包含子节点 放入子节点时fix父节点的背景色
        if (__parent__ !== undefined && __parent__.$el.style.backgroundColor === '#ffcc33') {
          __parent__.$el.style.backgroundColor = '';
        }
      }

      // 拖拽的虚拟节点
      let currentNode = vm.node;
      if (!(this.draggableMode === 'FROM')) { // 可拖拽 不在当前树通过拖拽进行新增或删除节点
        if (!(this.draggableMode === 'TO')) { // 可拖拽 不在当前树通过拖拽进行删除节点
          // 从拖拽的虚拟节点的父节点中删除拖拽的节点
          vm.$parent.node.menuChild = vm.$parent.node.menuChild.filter(function (node) {
            return node !== currentNode;
          });
        }
        let newNode;
        // es6深1层拷贝 多层时会出现节点的地址引用重复
        // new_node = {...vm.node};
        // new_node = Object.assign({}, vm.node);
        // 全部深层拷贝 多层时 子节点不会出现地址引用重复造成的联动
        newNode = JSON.parse(JSON.stringify(vm.node));
        // 虚拟节点的pid设置为目标节点的id
        newNode.pid = this.node.id;
        // 目标节点下新增虚拟节点
        this.node.menuChild.push(newNode);
      }
      this.$emit('handleDrop', currentNode);
    },
    // 当拖动停止时，会触发事件
    handleDragEnd: function () {
      this.$el.style.backgroundColor = '';
    },
    // 按下鼠标键并开始移动鼠标时执行
    handleDragStart: function (e) {
      this.show = false;
      window.__drop_node__ = this;
      this.$el.style.backgroundColor = '#00ffff';
    },
    // 有元素被拖动到放置目标上执行
    handleDragEnter: function () {
      this.$el.style.backgroundColor = '#ffcc33';
    },
    // 在元素被拖出放置目标时触发
    handleDragLeave: function () {
      this.$el.style.backgroundColor = '';
    },
    // 在被拖动的元素还在放置目标范围内移动时，会持续触发
    handleDragOver: function () {
    },
    // 子组件发送事件当前组件作为父组件处理发送来的事件
    // 传递事件到上一层
    childShowNodeDetail(node) {
      this.$emit('showNodeDetail', node);
    },
    childAddChildNode(node) {
      this.$emit('addChildNode', node);
    },
    childEditorNode(node) {
      this.$emit('editorNode', node);
    },
    childAddBrotherNode(node) {
      this.$emit('addBrotherNode', node);
    },
    childRemoveTreeNode(node) {
      this.$emit('removeNode', node);
    },
    childHandleDrop(node) {
      this.$emit('handleDrop', node);
    },
    childUpdateCheckBox(node) {
      this.$emit('updateCheckBox', node);
    },
    // 双击展开节点事件
    toggle: function () {
      if (this.isFolder) {
        // console.log(this.isFolder)
        this.$nextTick(() => {
          this.node.open = !this.node.open;
        });
      }
    },
    // 复选框点击事件
    selectCheck() {
      // 设置CheckBox失效不执行
      if (this.checkBoxDisabled) {
        return;
      }
      this.$emit('updateCheckBox', this.node);
    }
  }
};
</script>
<style lang="scss" scoped>
.rootLi {
  margin: 0;
  text-align: left;
}

.nodeLi {
  margin: 0 0 0 22px;
  white-space: nowrap;
}

.divNode {
  height: 32px;
  line-height: 32px;
  font-size: 32px;

  div {
    display: inline;
  }
}
</style>
